<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
  <title>scrolling_test.html</title>
  <script src="test_bootstrap.js"></script>
  <script type="text/javascript">
    goog.require('bot');
    goog.require('bot.action');
    goog.require('bot.dom');
    goog.require('goog.events');
    goog.require('goog.testing.ExpectedFailures');
    goog.require('goog.testing.jsunit');
    goog.require('goog.userAgent');
    goog.require('goog.userAgent.product');
  </script>
</head>
<body>
  <script type="text/javascript">
    var findElement = bot.locators.findElement;
    var expectedFailures;

    function setUp() {
      goog.events.removeAll();
      window.scrollTo(0, 0);
      assertEquals(document.body.scrollLeft, 0);
      assertEquals(document.body.scrollTop, 0);
      expectedFailures = new goog.testing.ExpectedFailures();
    }

    function tearDown() {
      expectedFailures.handleTearDown();
      window.scrollTo(0, 0); //Convenience to view results
    }

    function getTopLevelParent() {
      var document = bot.getDocument();
      return goog.userAgent.WEBKIT ? document.body : document.documentElement;
    }

    function testScrollsElementInToViewIfRequired() {
      bot.action.scrollIntoView(findElement({id: 'offscreen'}));

      expectedFailures.expectFailureFor(goog.userAgent.product.ANDROID,
        'Android doesn\'t currently provide scrolling information');
      expectedFailures.run(function() {
        assertNotEquals(0, getTopLevelParent().scrollLeft);
      });
    }

    function testDoesNotScrollElementInToViewIfAlreadyVisible() {
      bot.action.scrollIntoView(findElement({id: 'onscreen'}));
      assertEquals(0, getTopLevelParent().scrollLeft);
    }

    function testScrollsElementIfHiddenByScrollableOverflow() {
      var element = findElement({id: 'scrollable'});
      bot.action.scrollIntoView(element);
      assertNotEquals(0, findElement({id: 'scrollable-container'}).scrollLeft);
    }

    function testDoesNotScrollContainerIfNotHiddenByOverflow() {
      var element = findElement({id: 'scrollable-in-view'});
      bot.action.scrollIntoView(element);
      var container = findElement({id: 'scrollable-in-view-container'})
      assertEquals(0, container.scrollLeft);
    }

    function testDoesNotScrollContainerIfNotHiddenByOverflowWithOffset() {
      var element = findElement({id: 'scrollable-in-view2'});
      bot.action.scrollIntoView(element, new goog.math.Coordinate(0, 0));
      var container = findElement({id: 'scrollable-in-view-container2'})
      assertEquals(0, container.scrollLeft);
      assertEquals(0, getTopLevelParent().scrollTop);
    }

    function testScrollsContainerIfHiddenByOverflow() {
      bot.action.scrollIntoView(findElement({id: 'scrollable'}));
      assertNotEquals(0, findElement({id: 'scrollable-container'}).scrollLeft);
    }

    function testReturnsFalseIfElementHiddenByOverflow() {
      var element = findElement({id: 'hidden-by-overflow'});
      expectedFailures.expectFailureFor(
        true, // All browsers
        'This test checks that an element is not scrolled into view if its ' +
        'container has no scrollbars (overflow hidden). However, we ' +
        'currently allow this behaviour to get around cases where an ' +
        'element can be brought into view via other means.\n' +
        'Once we verify that there are other means (like moving inside a ' +
        'scrollable container by holding down the mouse button and moving) ' +
        'we should re-renable this test.');
      expectedFailures.run(function() {
        assertFalse(bot.action.scrollIntoView(element));
        var container = findElement({id: 'hidden-by-overflow-container'})
        assertEquals(0, container.scrollLeft);
      });
    }

    function testScrollsNestedScrollContainers() {
      var top = findElement({id: 'nested-top-container'});
      var middle = findElement({id: 'nested-inner-container'});
      var element = findElement({id: 'nested'});
      var nestedOriginalPosition = goog.style.getClientPosition(element);

      bot.action.scrollIntoView(element);

      var nestedNewPosition = goog.style.getClientPosition(element);
      assertNotEquals(0, top.scrollLeft);
      assertNotEquals(0, middle.scrollLeft);
      assertNotEquals(nestedOriginalPosition, nestedNewPosition);
    }

    function testOnlyScrollsContainersThatNeedScrolling() {
      var element = findElement({id: 'scrollable-but-unscrolled-not-hidden'});
      var origX = goog.style.getClientPosition(element).x;

      bot.action.scrollIntoView(element);

      var middleContainer = findElement({id:
          'scrollable-but-unscrolled-middle-container'});
      var topContainer = findElement({id:
          'scrollable-but-unscrolled-top-container'});

      expectedFailures.expectFailureFor(
          goog.userAgent.IE,
          'IE scrollIntoView scrolls quite eagerly.');
      expectedFailures.run(function() {
        assertNotEquals(0, topContainer.scrollLeft);
        assertEquals(0, middleContainer.scrollLeft);
        var newX = goog.style.getClientPosition(element).x;
        assertTrue(newX < origX);
      });
    }

    function testScrollsNestedScrollContainersInIframes() {
      var iframe = findElement({id: 'scrollable-iframe'});
      var frameDocument = iframe.contentWindow.document;
      var top =
        findElement({id: 'iframe-scrollable-top-container'}, frameDocument);
      var middle =
        findElement({id: 'iframe-scrollable-nested-container'}, frameDocument);
      var element = findElement({id: 'iframe-scrollable'}, frameDocument);

      bot.action.scrollIntoView(element);

      expectedFailures.expectFailureFor(goog.userAgent.product.ANDROID,
        'Android doesn\'t currently provide scrolling information');
      expectedFailures.run(function() {
        assertNotEquals(0, frameDocument.body.scrollLeft);
        assertNotEquals(0, top.scrollLeft);
        assertNotEquals(0, middle.scrollLeft);
      });
    }

    function testDocumentForIframe() {
      var iframe = findElement({id: 'offscreen-scrollable-iframe'});
      var frameDocument = iframe.contentWindow.document;
      var top =
        findElement({id: 'iframe-scrollable-top-container'}, frameDocument);
      var middle =
        findElement({id: 'iframe-scrollable-nested-container'}, frameDocument);
      var element = findElement({id: 'iframe-scrollable'}, frameDocument);

      bot.action.scrollIntoView(element);

      expectedFailures.expectFailureFor(goog.userAgent.product.ANDROID,
        'Android doesn\'t currently provide scrolling information');
      expectedFailures.run(function() {
        assertNotEquals(0, getTopLevelParent().scrollLeft);
        assertNotEquals(0, frameDocument.body.scrollLeft);
        assertNotEquals(0, top.scrollLeft);
        assertNotEquals(0, middle.scrollLeft);
      });
    }

    function testScrollsOverflowIfClickPointIsOutOfViewButElementIsInView() {
      var outer = findElement({id: 'outer'});
      var inner = findElement({id: 'inner'});
      var coord = new goog.math.Coordinate(75, 2500);
      expectedFailures.expectFailureFor(goog.userAgent.product.ANDROID,
        'Android doesn\'t currently provide scrolling information');
      expectedFailures.run(function() {
        assertTrue(bot.action.scrollIntoView(inner, coord));
        assertNotEquals(0, outer.scrollTop);
      });
    }
  </script>
  <div style="position: absolute; left: 150px; top: 100px; border: 2px yellow solid;"><a id="onscreen">Onscreen</a></div>
  <div style="position: absolute; left: 3000px; border: 2px orange solid;"><a id="offscreen">Offscreen</a></div>
  <div style="overflow: hidden; width: 50px; height: 30px; border: 2px blue solid;" id="hidden-by-overflow-container">
    <a style="margin-left: 100px;" id="hidden-by-overflow">Hidden</a></div>
  </div>
  <div id="scrollable-container" style="overflow: scroll; width: 100px; height: 100px; border: 2px purple solid;">
    <a id="scrollable" style="margin-left: 150px;">Scrollable</a>
  </div>
  <div id="scrollable-in-view-container" style="overflow: scroll; width: 200px;
    height: 50px; border: 2px grey solid;">&nbsp;&nbsp;&nbsp;<a
      id="scrollable-in-view">Scrollable&nbsp;in&nbsp;view</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  </div>
  <div id="scrollable-in-view-container2" style="overflow: scroll; width: 200px;
    height: 50px; border: 2px grey solid;">&nbsp;&nbsp;&nbsp;<a
      id="scrollable-in-view2">Scrollable&nbsp;in&nbsp;view</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  </div>
  <div style="overflow: hidden; width: 100px; height: 30px; border: 2px black solid;" id="not-hidden-by-hidden-overflow-container">&nbsp;&nbsp;&nbsp;<a id="not-hidden-by-hidden-overflow">Not hidden</a></div>
  <div style="overflow: scroll; width: 100px; height: 100px;" id="nested-top-container">
    <div style="overflow: scroll; width: 150px; left: 150px; margin-left:
      200px;" id="nested-inner-container"><a id="nested" style="margin-left: 200px;">Nested</a></div>
  </div>

  <div id="scrollable-but-unscrolled-top-container" style="overflow: scroll;
    width: 150px; height: 100px; border: 2px cyan solid;">
    <div id="scrollable-but-unscrolled-middle-container" style="overflow:
      scroll; width: 100px; height: 50px; border: 2px green solid; margin-left:
      200px">&nbsp;&nbsp;&nbsp;<a style="margin-right: 200px;"
        id="scrollable-but-unscrolled-not-hidden">X</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
  </div>

  <iframe src="testdata/scrolling_iframe.html" style="width: 200px; height: 100px;" id="scrollable-iframe"></iframe>
  <div style="position: absolute; left: 3000px; top: 200px; border: 2px orange solid;">
    <iframe src="testdata/scrolling_iframe.html" style="width: 200px; height: 100px;" id="offscreen-scrollable-iframe"></iframe>
  </div>

  <div style='overflow: scroll; width: 150px; height: 200px;' id="outer">
    <div style="width: 150px; height: 5000px;" id="inner">
    </div>
  </div>
</body>
</html>
